#include "input.h"
#include "debug.h"
#include "time.h"
#include "io.h"
#include "hal.h"

struct key_edge
{
    bool low_leve;
    bool high_leve;
};

static const struct io key_io[] =
{
    { GPIOA, GPIO_Pin_15 },
    { GPIOB, GPIO_Pin_5  },  
    { GPIOB, GPIO_Pin_6  },
    { GPIOB, GPIO_Pin_7  },  
};
static const int key_io_num = ARRAY_SIZE(key_io);

static struct key_edge key_edge[ARRAY_SIZE(key_io)];

static void __key_init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    
    RCC_AHBPeriphClockCmd( RCC_AHBPeriph_GPIOA | RCC_AHBPeriph_GPIOB, ENABLE ); 
    
    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_IN;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_40MHz;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_UP;
    GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_15;
    GPIO_Init( GPIOA, &GPIO_InitStructure ); 
    
    GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
    GPIO_Init( GPIOB, &GPIO_InitStructure ); 
}

static void key_timer_entry(union sigval p)
{
    int i;
    
    for( i = 0; i < key_io_num; i++ )
    {
        if( GPIO_ReadInputDataBit( key_io[i].gpio, key_io[i].pin ) == Bit_SET )
        {
            key_edge[i].high_leve = true;
        }
        
        if( true == key_edge[i].high_leve  )
        {
            if( GPIO_ReadInputDataBit( key_io[i].gpio, key_io[i].pin ) == Bit_RESET ) 
            {
                struct input_event input_event;
              
                key_edge[i].high_leve = false;
                input_event.value = i;
                
                input_report(INPUT_KEY_FALLING_EDGE_EVENT, &input_event);
            }
        }
    }
  
}

static err_t key_init(void)
{
    struct sigevent sigevent;
    struct itimerspect itimerspect;
    timer_t timer;
  
    __key_init();
    
    for (int i = 0; i < key_io_num; i++ )
    {
        key_edge[i].high_leve = false;
        key_edge[i].low_leve  = false;
    }
    
    sigevent.sigev_notify_function = key_timer_entry;
    sigevent.sigev_value.sival_ptr = NULL;
    sigevent.sigev_notify = SIGEV_THREAD;
    timer_create(CLOCK_REALTIME, &sigevent, &timer);
    ASSERT_KERNEL(timer != 0);
    
    itimerspect.it_interval.tv_nsec = 100;
    itimerspect.it_value.tv_nsec = 100;
    timer_settime(timer, 0, &itimerspect, NULL);
    
    input_open(INPUT_KEY_FALLING_EDGE_EVENT, O_CREAT | O_RDWR);
    
    return 0;
}
HAL_FUNC_EXPORT(key_init, init the key and its trigger scan timer, 1);
